package dslProgramGen;

import dslProgramGen.loopStatementsGenerators.*;
import methodCallTreeGen.MethodNode;
import methodCallTreeGen.Node;
import methodCallTreeGen.NodeType;

import java.util.*;

import static dslProgramGen.loopStatementsGenerators.util.TryToGenLoopStatementsUtil.sortProcessedStartAndEndIndexsPairListByStartIndexAscending;

/**
 * 尝试生成Loop语句的类
 */
public class TryToGenLoopStatements {
    /**
     * Loop语句最大检测范围
     */
//   public static LoopStatementsGenerator[] loopStatementsGenerators = {new TryToGenLoopStatementsFromContinuousSimilarLines(8)};
    public static int loopLineMaxNum = 8;
    /**
     * 遍历每一个函数，尝试生成Loop语句
     * @param methodNode
     */
    public static void tryToGenLoopStatementsForAllMethod(MethodNode methodNode) {
        tryToGenLoopStatementsForOneMethod(methodNode);
        // 遍历该methodNode的子函数节点
        for (Node node : methodNode.contentNodeList) {
            if (node.nodeType == NodeType.METHOD) {
                tryToGenLoopStatementsForAllMethod((MethodNode) node);
            }
        }
    }

    /**
     * 对一个函数尝试生成Loop语句
     * @param methodNode 尝试生成Loop语句的methodNode
     */
    public static void tryToGenLoopStatementsForOneMethod(MethodNode methodNode) {
        if (methodNode.isTriedToGenLoopStatement == true) {
            // 如果该函数之前处理过了
            return;
        }
        // 获得methodNode的DslExpressedMethod的函数体
        List<String> dslMethodContentList = methodNode.dslExpressedMethod.methodContentList;
        // 已经生成过Loop语句的DSL函数体的开始行和结束行pair对 列表
        List<List<Integer>> processedStartAndEndIndexsPairList = new ArrayList<>();
        // 已经生成过Loop语句的DSL函数体开始行和结束行pair对 To 对应的DSL语句列表; key表示开始行和结束行组成的String，value表示对应的Loop语句
        Map<String, List<String>> startAndEndIndexs2LoopStatementListMap = new HashMap<>();
        // 对每一个Loop generator算子，尝试产生Loop语句
        //for (LoopStatementsGenerator loopStatementsGenerator : loopStatementsGenerators) {
        for(int i=1; i<loopLineMaxNum+1;i++){
            LoopStatementsGenerator loopStatementsGenerator = new TryToGenLoopStatementsFromContinuousSimilarLines(i);
            // 获得dslMethodContentList中未被生成Loop语句的Snippet片段开始和结束下标列表（要求Snippet片段至少有两行）
            List<List<Integer>> unprocessedStartAndEndIndexsPairList = searchUnprocessedStartAndEndIndexsPairList(processedStartAndEndIndexsPairList, dslMethodContentList.size());
            if (unprocessedStartAndEndIndexsPairList.size() == 0) {
                // 没有未生成Loop语句的Snippet片段
                break;
            }
            // 对每个未生成Loop语句的Snippet片段尝试使用当前算子生成Loop语句
            for (List<Integer> unprocessedStartAndEndIndexsPair : unprocessedStartAndEndIndexsPairList) {
                loopStatementsGenerator.tryToGenLoopStatementInASnippet(dslMethodContentList,
                        unprocessedStartAndEndIndexsPair,
                        processedStartAndEndIndexsPairList,
                        startAndEndIndexs2LoopStatementListMap);
            }
        }
        // 如果该函数没有生成Loop语句，直接返回
        if (processedStartAndEndIndexsPairList.size() == 0) {
            return;
        }
        // 说明函数有生成Loop语句
        // 生成有Loop语句的新的dslMethodContentList函数体
        List<String> dslMethodContentListWithLoopStatement = new ArrayList<>();
        // 将已经生成过Loop语句的DSL函数体的开始行和结束行pair对 列表 按start升序排序
        sortProcessedStartAndEndIndexsPairListByStartIndexAscending(processedStartAndEndIndexsPairList);
        // 当前生成Loop语句的Pair在ProcessedStartAndEndIndexsPairList中的下标
        int currentProcessedPairIndexOfProcessedStartAndEndIndexsPairList = 0;
        int processedPairStartIndex = processedStartAndEndIndexsPairList.get(currentProcessedPairIndexOfProcessedStartAndEndIndexsPairList).get(0);
        // 遍历旧的dslMethodContentList，将产生Loop语句的地方替换为Loop语句，保存在dslMethodContentListWithLoopStatement中
        for (int i = 0; i < dslMethodContentList.size(); i++) {
            if (i != processedPairStartIndex) {
                // 如果dslMethodContentList该行内容不是Loop语句开始的位置,复制该行语句到dslMethodContentListWithLoopStatement
                dslMethodContentListWithLoopStatement.add(dslMethodContentList.get(i));
            } else {
                // 表示dslMethodContentList该行开始产生Loop语句
                // 获得Loop语句在dslMethodContentList结束下标
                int processedPairEndIndex = processedStartAndEndIndexsPairList.get(currentProcessedPairIndexOfProcessedStartAndEndIndexsPairList).get(1);
                // 获得产生的Loop语句列表
                List<String> loopStatementsList = startAndEndIndexs2LoopStatementListMap.get("[" + processedPairStartIndex + ", " + processedPairEndIndex + ")");
                // 将Loop语句列表添加到dslMethodContentListWithLoopStatement
                dslMethodContentListWithLoopStatement.addAll(loopStatementsList);
                // 更新currentProcessedPairIndexOfProcessedStartAndEndIndexsPairList与processedPairStartIndex
                if (currentProcessedPairIndexOfProcessedStartAndEndIndexsPairList + 1 < processedStartAndEndIndexsPairList.size()) {
                    currentProcessedPairIndexOfProcessedStartAndEndIndexsPairList++;
                    processedPairStartIndex = processedStartAndEndIndexsPairList.get(currentProcessedPairIndexOfProcessedStartAndEndIndexsPairList).get(0);
                }
                // 更新i
                i = processedPairEndIndex - 1;
            }
        }
        // 将methodNode.dslExpressedMethod.methodContentList替换成有Loop语句的循环体
        methodNode.dslExpressedMethod.methodContentList = dslMethodContentListWithLoopStatement;
        // 标记该函数已尝试生成Loop语句
        methodNode.isTriedToGenLoopStatement = true;
    }



    /**
     * 现在dslMethodContentList已经被处理了一部分（生成了Loop语句），处理过的[start, end) pair对存储在processedStartAndEndIndexsPairList，该函数想返回未生成Loop语句的[start, end) pair对
     * @param processedStartAndEndIndexsPairList 之前已经生成过Loop语句的DSL函数体的开始行和结束行pair对 列表
     * @param dslMethodContentListSize dslMethodContentList的行数
     * @return 未生成Loop语句的[start, end) pair对 列表
     */
    public static List<List<Integer>> searchUnprocessedStartAndEndIndexsPairList(List<List<Integer>> processedStartAndEndIndexsPairList, int dslMethodContentListSize) {
        // 先对处理过的[start, end) pair对按start升序排列
        // 按第二维的第一个元素进行排序
        sortProcessedStartAndEndIndexsPairListByStartIndexAscending(processedStartAndEndIndexsPairList);
        // 想找到未生成Loop语句的pair对
        List<List<Integer>> unprocessedStartAndEndIndexsPairList = new ArrayList<>();
        int lastEndIndex = 0; // 上一个结束的index
        for (int i = 0; i < processedStartAndEndIndexsPairList.size(); i++) {
            List<Integer> processedStartAndEndIndexsPair = processedStartAndEndIndexsPairList.get(i);
            // 获得processedStartAndEndIndexsPair开始下标
            int processedStartIndex = processedStartAndEndIndexsPair.get(0);
            if (lastEndIndex != processedStartIndex) {
                // 说明有未被处理的index
                if (processedStartIndex - lastEndIndex != 1) {
                    // 等于1说明只有一个元素没有被处理，这里不等于1说明有至少两个元素没有被处理
                    List<Integer> unprocessedStartAndEndIndexsTempList = Arrays.asList(lastEndIndex, processedStartIndex);
                    unprocessedStartAndEndIndexsPairList.add(unprocessedStartAndEndIndexsTempList);
                }
            }
            // 重置lastEndIndex为processedStartAndEndIndexsPair的结束下标
            lastEndIndex = processedStartAndEndIndexsPair.get(1);
        }
        if (lastEndIndex < dslMethodContentListSize) {
            // 表明最后一个processedStartAndEndIndexsPair未能覆盖到结束，即[processedStartAndEndIndexsPair的end, maxSize)未生成Loop语句
            if (dslMethodContentListSize - lastEndIndex != 1) {
                // 等于1说明只有一个元素没有被处理，这里不等于1说明有至少两个元素没有被处理
                List<Integer> unprocessedStartAndEndIndexsTempList = Arrays.asList(lastEndIndex, dslMethodContentListSize);
                unprocessedStartAndEndIndexsPairList.add(unprocessedStartAndEndIndexsTempList);
            }
        }
        return unprocessedStartAndEndIndexsPairList;
    }
}
